﻿//-----------------------------------------------------------------------
// <copyright file="HtmlExtensions.cs" company="Sławomir Rosiek">
//     Copyright (c) Sławomir Rosiek. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Rosieks.Web.Flow.Html
{
    using System.Collections.Generic;
    using System.Web.Mvc;
    using System.Web.Mvc.Html;
    using System.Web.Routing;
    using System.Linq;
    using Rosieks.Web.Flow.Metadata;
    using System;
    using Rosieks.Web.Flow.Resources;
using System.Linq.Expressions;
using System.Web.WebPages;
    using System.Text;

    public static class HtmlExtensions
    {
        internal const string WebflowModelViewDataKey = "__WebflowModel_ViewData_Key";

        public static MvcHtmlString FlowButton(this HtmlHelper html, string buttonText, string actionName)
        {
            return html.FlowButton(buttonText, actionName, null);
        }

        public static MvcHtmlString FlowButton(this HtmlHelper html, string buttonText, string actionName, object htmlAttributes)
        {
            return html.FlowButton(buttonText, actionName, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString FlowButton(this HtmlHelper html, string buttonText, string actionName, IDictionary<string, object> htmlAttributes)
        {
            Transition transition = HtmlExtensions.GetTransitionFor(html, actionName);

            TagBuilder buttonBuilder = new TagBuilder("input");
            buttonBuilder.MergeAttributes(htmlAttributes);
            buttonBuilder.MergeAttribute("name", string.Format("ActionName.{0}", actionName), true);
            buttonBuilder.MergeAttribute("type", "submit");
            buttonBuilder.MergeAttribute("value", buttonText);
            if (transition != null)
            {
                buttonBuilder.MergeAttribute("data-flow-default", transition.IsDefault.ToString().ToLower());

                if (!transition.RequireValidModel)
                {
                    buttonBuilder.MergeAttribute("data-val-ignore-rules", (!transition.RequireValidModel).ToString().ToLower());
                }
            }

            TagBuilder hiddenBuilder = new TagBuilder("input");
            hiddenBuilder.MergeAttribute("name", "ActionName");
            hiddenBuilder.MergeAttribute("type", HtmlHelper.GetInputTypeString(InputType.Hidden));
            hiddenBuilder.MergeAttribute("value", actionName);

            return MvcHtmlString.Create(buttonBuilder.ToString(TagRenderMode.SelfClosing) + hiddenBuilder.ToString(TagRenderMode.SelfClosing));
        }        

        public static MvcHtmlString FlowImageButton(this HtmlHelper html, string imageUrl, string imageText, string actionName)
        {
            return html.FlowImageButton(imageUrl, imageText, actionName, new RouteValueDictionary());
        }

        public static MvcHtmlString FlowImageButton(this HtmlHelper html, string imageUrl, string imageText, string actionName, object htmlAttributes)
        {
            return html.FlowImageButton(imageUrl, imageText, actionName, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
        }

        public static MvcHtmlString FlowImageButton(this HtmlHelper html, string imageUrl, string imageText, string actionName, IDictionary<string, object> htmlAttributes)
        {
            var url = new UrlHelper(html.ViewContext.RequestContext);

            htmlAttributes["type"] = "image";
            htmlAttributes["src"] = url.Content(imageUrl);

            return html.FlowButton(imageText, actionName, htmlAttributes);
        }

        public static MvcHtmlString FlowLink(this HtmlHelper html, string linkText, string actionName, object htmlAttributes)
        {
            return html.FlowLink(linkText, actionName, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString FlowLink(this HtmlHelper html, string linkText, string actionName, IDictionary<string, object> htmlAttributes)
        {
            var webflowContext = WebflowContext.GetCurrent(html.ViewContext.HttpContext);

            var currentStateRoute = webflowContext.CurrentState.RouteData;

            var routeLinkValues = new RouteValueDictionary(currentStateRoute.Values);
            routeLinkValues.Add("actionName", actionName);

            return html.RouteLink(linkText, currentStateRoute.RouteName, routeLinkValues, htmlAttributes);
        }

        public static TWebflowModel GetWebflowModel<TWebflowModel>(this ViewDataDictionary viewData)
        {
            return (TWebflowModel)viewData[WebflowModelViewDataKey];
        }

        public static MvcHtmlString FlowForm(this HtmlHelper html)
        {
            StringBuilder sb = new StringBuilder();

            object webflowContextValue;
            if (html.ViewData.TryGetValue(HiddenFieldWebflowContextProvider.WebflowContextKey, out webflowContextValue))
            {
                TagBuilder tag = new TagBuilder("input");
                tag.MergeAttribute("type", "hidden");
                tag.MergeAttribute("name", HiddenFieldWebflowContextProvider.WebflowContextKey);
                tag.MergeAttribute("value", (string)webflowContextValue);
                sb.AppendLine(tag.ToString());
            }

            return MvcHtmlString.Create(sb.ToString());
        }

        private static Transition GetTransitionFor(HtmlHelper html, string actionName)
        {
            Transition transition = null;
            var webflowContext = WebflowContext.GetCurrent(html.ViewContext.HttpContext);
            if (webflowContext != null)
            {
                if (!ActionTransition.TryParse(actionName, webflowContext, out transition))
                {
                    transition = webflowContext.CurrentState.Transitions.FirstOrDefault(f => f.On == actionName);
                };

                if (transition == null)
                {
                    throw new ArgumentException(string.Format(WebflowResources.Common_InvalidActionName, actionName, webflowContext.CurrentStateName), "actionName");
                }
            }

            return transition;
        }
    }
}
